package han.chensing.latos.maker.windows.widget;

import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.Widget;

import java.util.ArrayList;
import java.util.List;

import han.chensing.latos.maker.GameMain;
import han.chensing.latos.common.level.sample.Sample;
import han.chensing.latos.maker.windows.dialog.sample.SampleImportFromMidiDialog;

public class MidiSelectorWidget extends Widget {

    SampleImportFromMidiDialog.TrackSet track;
    float nowTime;
    float speed=0.5f;

    float dragStartX;
    float dragStartTime;
    float scalingStartSpeed;
    float selectingStartX=-1,selectingStartY=-1;
    float selectingX,selectingY;
    boolean dragging =false;
    boolean scaling=false;
    boolean selecting=false;

    public MidiSelectorWidget(){
        addListener(new InputListener(){
            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                switch (button){
                    case Input.Buttons.LEFT:{
                        dragStartX=x;
                        dragStartTime=nowTime;
                        dragging =true;
                        break;
                    }
                    case Input.Buttons.RIGHT:{
                        selecting=true;
                        selectingStartX=selectingX=x;
                        selectingStartY=selectingY=y;
                        break;
                    }
                    case Input.Buttons.MIDDLE:{
                        scalingStartSpeed=speed;
                        dragStartX=x;
                        scaling=true;
                        break;
                    }
                }
                return true;
            }

            @Override
            public void touchDragged(InputEvent event, float x, float y, int pointer) {
                super.touchDragged(event, x, y, pointer);
                if (track==null)
                    return;
                if (dragging){
                    float delta = dragStartX-x;
                    float deltaTime = delta / speed;
                    float newTime = dragStartTime + deltaTime;
                    newTime=newTime>track.totalTime?track.totalTime:
                            (newTime<0?0:newTime);
                    updateFlow(newTime/track.totalTime*100f);
                }
                if (scaling){
                    float delta = x-dragStartX;
                    speed=Math.max(0.01f,scalingStartSpeed+delta*0.005f);
                }
                if (selecting){
                    selectingX=x;
                    selectingY=y;
                }
            }

            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                super.touchUp(event, x, y, pointer, button);
                ArrayList<Sample> selectedSamples = getSelectedSamples();
                SampleImportFromMidiDialog sampleImportFromMidiDialog = (SampleImportFromMidiDialog) getParent();
                sampleImportFromMidiDialog.updateTempSamplesList(selectedSamples);
                dragging=false;
                scaling=false;
                selecting=false;
                selectingStartX=selectingStartY=-1;
            }
        });
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        validate();
        //batch.draw(Res.get().get("tapT", Texture.class),0,0);
        float width = getWidth();
        float height = getHeight();
        float centerLine = width / 2f;
        GameMain.shapeDrawer.filledRectangle(getX(),getY(), width,getHeight(),Color.BLACK);
        if (track!=null) {
            drawSamples(track.oriSamples);
            drawSamples(track.samples);
        }
        if (selectingStartX!=-1) {
            GameMain.shapeDrawer.rectangle(
                    getX() + selectingStartX, getY() + selectingStartY,
                    selectingX-selectingStartX ,
                    selectingY-selectingStartY);
        }
        GameMain.shapeDrawer.line(centerLine+getX(),getY(),centerLine+getX(),height+getY(),2, Color.BLUE, Color.WHITE);
    }

    private ArrayList<Sample> getSelectedSamples(){
        List<Sample> samples = track.oriSamples;
        ArrayList<Sample> outSamples=new ArrayList<>();
        float halfCanvasTime = getWidth() / 2f / speed;
        for (Sample sample : samples) {
            float absTime = sample.getTime();
            float offset = absTime - nowTime;
            if (Math.abs(offset) >= halfCanvasTime)
                continue;
            boolean sampleInSelect = isSampleInSelect(sample);
            if (sampleInSelect)
                outSamples.add(sample);
        }
        return outSamples;
    }

    public void updateFlow(float time){
        if (track==null)
            return;
        this.nowTime=time/100f*track.totalTime;
    }

    public void updateMidiTrack(SampleImportFromMidiDialog.TrackSet trackSet){
        this.track=trackSet;
    }

    public void drawSamples(List<Sample> samples){
        float halfCanvasTime = getWidth() / 2f / speed;
        for (Sample sample : samples) {
            float absTime = sample.getTime();
            float offset = absTime - nowTime;
            if (Math.abs(offset) >= halfCanvasTime)
                continue;
            float canvasTime = offset + halfCanvasTime;
            float canvasPos = canvasTime * speed;
            boolean sampleInSelect = isSampleInSelect(sample);
            Color color = !sampleInSelect?Color.FOREST:Color.CYAN;
            GameMain.shapeDrawer.line(getX() + canvasPos, getY(),
                    getX() + canvasPos, getY() + getHeight(),
                    2, color, color);
        }
    }

    private boolean isSampleInSelect(Sample sample){
        if (selectingStartX==-1)
            return false;
        float centerLine = getWidth() / 2;
        float fromTimeDelta=(selectingStartX-centerLine)/speed;
        float toTimeDelta=(selectingX-centerLine)/speed;
        if (fromTimeDelta>toTimeDelta){
            float temp=fromTimeDelta;
            fromTimeDelta=toTimeDelta;
            toTimeDelta=temp;
        }
        float fromTime=nowTime+fromTimeDelta;
        float toTime=nowTime+toTimeDelta;
        return sample.getTime()>=fromTime&&sample.getTime()<=toTime;
    }
}